package nl.boektrust.btsoep.client;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import nl.boektrust.btsoep.shared.model.Contributor;
import nl.boektrust.btsoep.shared.model.Person;
import nl.boektrust.btsoep.shared.model.PhysicalBookManifestation;

import com.google.gwt.cell.client.ClickableTextCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.SimplePager.TextLocation;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.SelectionChangeEvent;


public class MensenPanel extends VerticalPanel implements ClickHandler, KeyPressHandler,KeyUpHandler {
	Button newMensButton = new Button("Nieuw");
	Button editMensButton = new Button("Bewerk");
	Button filterMensButton = new Button("Filter");
	Button deleteMensButton = new Button("Verwijder");
	Button rememberMensButton = new Button("Onthoud");
	final Label feedbackLabel = new Label("");
	TextBox topTextBox = new TextBox();
	static int minimumFilterLength = 3;
	PersistentServiceAsync persistentService;
	ListDataProvider<Person> dataProvider;
	Btsoep btsoep;
	
	// The list of data to display.
	public void populatePersonsArray(ListDataProvider<Person> dataProvider) {
		final List<Person> list = dataProvider.getList();
		/*
		 * don't load data if the topTextBox has no or little text. 
		 */
		if (topTextBox.getValue().length() < minimumFilterLength) return;
		try {
			if (topTextBox.getValue().startsWith("978")) {
				feedbackLabel.setText("Opzoeken op ISBN, wacht aub.");
				persistentService.getBooksByISBN(topTextBox.getValue(), new AsyncCallback<List<PhysicalBookManifestation>> () {
					public void onFailure(Throwable caught) {
						System.out.println("MensenPanel.java (person): onClick(): PersistentService RPC call failed " + caught);
						feedbackLabel.setText("Error: persistentRPC call mislukt, zie logs voor detail.");
					}
					public void onSuccess(List<PhysicalBookManifestation> result) {
						Set<Person> personSet = new HashSet<Person>();
						for (PhysicalBookManifestation pbm : result) {
							for (Contributor c : pbm.getContributors()) {
								if (c.getPerson() != null)	personSet.add(c.getPerson());
							}
						}
						list.clear();
						for (Person person : personSet) {
							if (list.size() < 200) {
								person.setSelected(false);
								getNumberOfBooksForPerson(person);
								list.add(person);
							}
						}
						feedbackLabel.setText("Gevonden: "+list.size()+" personen (zoeklimiet: 200)");

					}
				});

			} else {
				feedbackLabel.setText("Opzoeken op naam, wacht aub.");

				persistentService.getPersonsByPartialName(topTextBox.getValue(), new AsyncCallback<List<Person>>() {
				//		@Override
				public void onFailure(Throwable caught) {
					System.out.println("MensenPanel.java (person): onClick(): PersistentService RPC call failed " + caught);
					feedbackLabel.setText("Error: persistentRPC call mislukt, zie logs voor detail.");
				}

				//      @Override
				public void onSuccess(List<Person> result) {
					/*
                    	Log.debug("getallpersons: success");
                    	Log.debug("MensenPanel.java (person): onClick(): PersistentService RPC call succeeded; received a list with "+result.size()+" elements");
					 */
					list.clear();
					for (Person person : result) {
						person.setSelected(false);
						getNumberOfBooksForPerson(person);
						list.add(person);
					}
					feedbackLabel.setText("Gevonden: "+list.size()+" personen (zoeklimiet: 200)");

					//Log.debug("in onSuccess, personList has " + personList.size() + " elements");
				}

			});
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	class MyCallback implements AsyncCallback<List<PhysicalBookManifestation>> {
		Person p;
		public void onFailure(Throwable caught) {
        	System.out.println("MensenPanel.java: getNumberOfBooksForPerson: PersistentService RPCgetBooksForPerson call failed " + caught);
                }

  //      @Override
        public void onSuccess(List<PhysicalBookManifestation> result) {
        	p.setBooksContributedTo(result);
        	dataProvider.refresh();
        	return;
        }
	}
	
	void getNumberOfBooksForPerson(Person p) {
		try {
			MyCallback myCallback = new MyCallback();
			myCallback.p = p;
			persistentService.getBooksForPerson(p, myCallback);
		} catch (Exception e) {
    		e.printStackTrace();
    	}
	}

	public void loadData() {
		System.out.println("loadData called");
	    populatePersonsArray(dataProvider);
	}

	public MensenPanel(Btsoep btsoep) {
		persistentService = GWT.create(PersistentService.class);
		this.btsoep = btsoep;

		// Instantiate the interfaces to access methods in the interface
		this.buildTopPanel();
		this.add(feedbackLabel);
		this.buildTable();
	}
	 /**
	   * The key provider that allows us to identify Contacts even if a field
	   * changes. We identify contacts by their unique ID.
	   */
	  private static final ProvidesKey<Person> KEY_PROVIDER = new ProvidesKey<Person>() {
	    public Object getKey(Person item) {
	      return item.getId();
	    }
	  };
	private void buildTable() {
		//ScrollPanel sp = new ScrollPanel();
		// Create a celltable
		final CellTable<Person> personTable = new CellTable<Person>(KEY_PROVIDER);
		// Create name column
	    final TextCell nameCell = new TextCell();
	  
		Column<Person, String> nameColumn = new Column<Person, String>(nameCell) {
			@Override
			public String getValue(Person person) {
				return person.getName();
			}
		};
		/*nameColumn.setFieldUpdater(new FieldUpdater<Person,String>() {
			public void update(int index, Person object, String value) {
				System.out.println("field updater called");
		       // pendingChanges.add(new FirstNameChange(object, value));
		      }
		});*/
		// Make the name column sortable.
	    nameColumn.setSortable(true);
	    //personTable.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
		personTable.addColumn(nameColumn, "Naam");
		
		// Create birth/deceased column
		TextColumn<Person> birthPlaceColumn = new TextColumn<Person>() {
			@Override
			public String getValue(Person person) {
				return person.displayableBirthDeceasedString();
			}
		};
		personTable.addColumn(birthPlaceColumn, "Geboren/Gestorven");
		// Make the name and birthcolumn sortable.
		birthPlaceColumn.setSortable(true);
		
		TextColumn<Person> identifierDaiColumn = new TextColumn<Person>() {
			@Override
			public String getValue(Person person) {
				return person.getIdentifier_dai();
			}
		};
		personTable.addColumn(identifierDaiColumn, "DAI");
		
		TextColumn<Person> identifierViafColumn = new TextColumn<Person>() {
			@Override
			public String getValue(Person person) {
				return person.viafToString();
			}
		};
		personTable.addColumn(identifierViafColumn, "VIAF");

		final ValueUpdater <String> valueUpdater = new ValueUpdater<String>() {
			public void update(String newValue) {
	        Window.alert("You typed: " + newValue);
	      }
		};
		
		FieldUpdater<Person, String> biographicalColumnFieldUpdater = new FieldUpdater<Person, String>() {
			public void update(int index, Person object, String value) {
		        Window.alert("Biografisch: " + object.getBiographical());
		      }
		};
		FieldUpdater<Person, String> urlColumnFieldUpdater = new FieldUpdater<Person, String>() {
			public void update(int index, Person object, String value) {
		        Window.alert("URL: " + object.getUrl());
		      }
		};
		// Create biographical column
		Column<Person, String> biographicalColumn = new Column<Person, String>(new ClickableTextCell()) {
			@Override
			public String getValue(Person person) {
				if (person != null && person.getBiographical() != null && person.getBiographical().length() > 40) {
					return person.getBiographical().substring(0,36) + " ...";
				} 
				return person.getBiographical();
			}
		};
		personTable.addColumn(biographicalColumn, "Biografisch");
		biographicalColumn.setFieldUpdater(biographicalColumnFieldUpdater);
		// Make the name and birthcolumn sortable.
		biographicalColumn.setSortable(false);
		
		// Create URL column
		Column <Person, String> urlColumn = new Column <Person, String> (new ClickableTextCell()) {
			@Override
			public String getValue(Person person) {
				if (person.getUrl().length() > 40) {
					return person.getUrl().substring(0,36) + " ...";
				} 
				return person.getUrl();
			}
		};
		urlColumn.setFieldUpdater(urlColumnFieldUpdater);
		
		personTable.addColumn(urlColumn, "URL");
		// Make the name and birthcolumn sortable.
		urlColumn.setSortable(false);
		
		// Create URL column
		TextColumn<Person> booksColumn = new TextColumn<Person>() {
			@Override
			public String getValue(Person person) {
				String isbns = new String("");
				isbns = isbns + new Integer(person.getNumberOfBooksContributedTo()).toString();
				if (person.getBooksContributedTo() != null) {
					isbns = isbns + ": ";
					for (PhysicalBookManifestation b : person.getBooksContributedTo()) {
						isbns += new Long(b.getRecordReference()).toString() + ", ";
					}
				}
				return isbns;
			}
		};
		personTable.addColumn(booksColumn, "Boeken");
		// Make the name and birthcolumn sortable.
		booksColumn.setSortable(true);
		
	    // Create a data provider.
	    dataProvider = new ListDataProvider<Person>();

	    // Connect the table to the data provider.
	    dataProvider.addDataDisplay(personTable);

	    // Add the data to the data provider, which automatically pushes it to the
	    // widget.
	    List<Person> list = dataProvider.getList();
	    loadData();
	 // Add a selection model to handle user selection.
	    final MultiSelectionModel<Person> selectionModel = new MultiSelectionModel<Person>();
	    personTable.setSelectionModel(selectionModel);
	    selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
		      public void onSelectionChange(SelectionChangeEvent event) {
		    	  
		    	  Set<Person> selectedSet = selectionModel.getSelectedSet();
		    	  
		    	  if (selectedSet.size() == 0) {
	    			  editMensButton.setEnabled(false);
		    		  deleteMensButton.setEnabled(false);
		    		  rememberMensButton.setEnabled(false);
		    	  } else {
		    		  // determine which persons are selected
		    		  List<Person> list = dataProvider.getList();
		    		  for (Person p : list) {
			    		  if (selectedSet.contains(p)) {
			    			  p.setSelected(true);
			    		  } else {
			    			  p.setSelected(false);
			    		  }
			    	  }
		    		  // reset state of the buttons. 
		    		  if (selectedSet.size() == 1) editMensButton.setEnabled(true); else editMensButton.setEnabled(false);
		    		  if (selectedSet.size() >= 1) deleteMensButton.setEnabled(true);
		    		  rememberMensButton.setEnabled(true);
		    	  }
		    	  //Person selected = selectionModel.getSelectedObject();
		    	  //if (selected != null) {
		    		//  EditMensDialog editMensDialogBox = new EditMensDialog(selected, mensenPanel);
		    		 // editMensDialogBox.show();
		    	  //}
		      }
		    });
	    //personTable.setSelectionModel(selectionModel);
	    /*
	    DefaultSelectionEventManager<Person> selectionEventManager = DefaultSelectionEventManager.createCustomManager(new DefaultSelectionEventManager.CheckboxEventTranslator<Person>() {
	    	@Override
	    	public SelectAction translateSelectionEvent(CellPreviewEvent<Person> event) {
                SelectAction action = super.translateSelectionEvent(event);
                if (action.equals(SelectAction.IGNORE)) {
                    GWT.log("DO WHAT YOU WANT!!!");
                    return SelectAction.IGNORE;
                }
                return action;
            }
	    });
	    personTable.setSelectionModel(selectionModel, selectionEventManager);
	    */
	   /* */

	    // add a pager
	    SimplePager pager;
	    SimplePager.Resources pagerResources = GWT.create(SimplePager.Resources.class);
	    pager = new SimplePager(TextLocation.CENTER, pagerResources, true, 0,true);
	    pager.setDisplay(personTable);
	    pager.setPageSize(25);
	    // Add a ColumnSortEvent.ListHandler to connect sorting to the
	    // java.util.List.
	    ListHandler<Person> columnSortHandler = new ListHandler<Person>(list);
	    columnSortHandler.setComparator(booksColumn, new Comparator<Person>() {
	    	public int compare(Person o1, Person o2) {
	    		return 0;
	    		//if (o1.get == o2) return 0;
	    		//if (o1 > o2) return 1; else return -1;
	    	}
	    });
	    columnSortHandler.setComparator(nameColumn,
	    		new Comparator<Person>() {
	    	public int compare(Person o1, Person o2) {
	    		String o1Key = o1.lastPartOfName();
	    		if (o1.getName().length() > o1Key.length()) o1Key += o1.getName();
	    		String o2Key = o2.lastPartOfName();
	    		if (o2.getName().length() > o2Key.length()) o2Key += o2.getName();

	    		if (o1 == o2) {
	    			return 0;
	    		}

	    		// Compare the name columns.
	    		if (o1 != null) {
	    			return (o2 != null) ? o1Key.compareTo(o2Key) : 1;
	    		}
	    		return -1;
	    	}
	    });
	    personTable.addColumnSortHandler(columnSortHandler);

	    // We know that the data is sorted alphabetically by default.
	    personTable.getColumnSortList().push(nameColumn);
	    this.add(personTable);
	    this.add(pager);

		//todo: http://code.google.com/p/google-web-toolkit-incubator/wiki/PagingScrollTable
	}
	
	
	private void buildTopPanel() {
		HorizontalPanel topPanel = new HorizontalPanel();
		/* add the 'new' button */
		newMensButton.addClickHandler(this);
		deleteMensButton.addClickHandler(this);
		editMensButton.addClickHandler(this);
		filterMensButton.addClickHandler(this);
		rememberMensButton.addClickHandler(this);
		
		topTextBox.addKeyPressHandler(this);
		topTextBox.addKeyUpHandler(this);
		
		topPanel.add(new Label("Selectie: "));
		topPanel.add(topTextBox);
		topPanel.add(filterMensButton);
		topPanel.add(newMensButton);
		topPanel.add(editMensButton);
		topPanel.add(deleteMensButton);
		topPanel.add(rememberMensButton);
		editMensButton.setEnabled(false);
		deleteMensButton.setEnabled(false);
		filterMensButton.setEnabled(false);
		rememberMensButton.setEnabled(false);
		this.add(topPanel);
	}
	
	public void onClick(ClickEvent event) {
	    // note that in general, events can have sources that are not Widgets.
	    Widget sender = (Widget) event.getSource();
	    feedbackLabel.setText("");

	    if (sender == newMensButton) {
			editMensButton.setEnabled(false);
			deleteMensButton.setEnabled(false);

	    	Person p = new Person();
        	EditMensDialog editMensDialogBox = new EditMensDialog(p, this);
        	editMensDialogBox.panel = this;
        	editMensDialogBox.show();
	    } else if (sender == filterMensButton) {
	    	loadData();
	    } else if (sender == deleteMensButton) {
	    	editMensButton.setEnabled(false);
			deleteMensButton.setEnabled(false);
		    feedbackLabel.setText("Verwijderen van persoon, even wachten...");

			final List<Person> list = dataProvider.getList();
			for (Person p: list) {
				if (p.isSelected()==true) {
					try {
						persistentService.deletePerson(p, new AsyncCallback<Void>() {
							public void onFailure(Throwable caught) {
								System.out.println("MensenPanel.java (person): onClick(): PersistentService RPC call failed " + caught);
							}
							public void onSuccess(Void a) {
								System.out.println("person deleted");
							    feedbackLabel.setText("Persoon verwijderd.");
							    loadData();

							}

						});
					} catch (Exception e) {
						e.printStackTrace();
					}
				} 
			} 
		    loadData();

	    } else if (sender == editMensButton) {
			final List<Person> list = dataProvider.getList();
			for (Person p: list) {
				if (p.isSelected()==true) {
		        	EditMensDialog editMensDialogBox = new EditMensDialog(p, this);
		        	editMensDialogBox.show();
				}
			}
	    } else if (sender == rememberMensButton) {
	    	final List<Person> list = dataProvider.getList();
			for (Person p: list) {
				if (p.isSelected()==true) {
					btsoep.addPersonToStoredPersonsList(p);
				}
			}
	    }

	}
	
	public void onKeyPress(KeyPressEvent event) {
	    Widget sender = (Widget) event.getSource();
	}

	public void onKeyUp(KeyUpEvent event) {
	    Widget sender = (Widget) event.getSource();
	    if (sender == topTextBox) {
	    	if (((TextBox)sender).getValue().length() >= minimumFilterLength) {
	    		this.filterMensButton.setEnabled(true);
	    	} else {
	    		this.filterMensButton.setEnabled(false);
	    	}
	    	// add action to perform here
	    	
	    	
	    }
	
	}

}
